home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / Apps / EmacsTeX / emacs-patches / src / unexNeXT.c < prev   
Encoding:
C/C++ Source or Header  |  1992-09-06  |  8.8 KB  |  419 lines

  1. /*
  2.  * unexec for the NeXT Mach environment.
  3.  *
  4.  * Bradley Taylor (btaylor@NeXT.COM)
  5.  * February 28, 1990
  6.  *
  7.  * Modified 9/6/92 by Charles Swiger (cs4w@andrew.cmu.edu) for usability
  8.  * with Emacs 18.58 & general neatness.
  9.  *
  10.  */
  11.  
  12. #ifdef NeXT
  13.  
  14. #undef __STRICT_BSD__
  15.  
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <stdarg.h>
  19. #include <mach.h>
  20. #include <sys/loader.h>
  21. #include <sys/file.h>
  22. #include <sys/stat.h>
  23. #include <libc.h>
  24.  
  25. extern int malloc_freezedry();  /* get rid of "implicit decl" message */
  26.  
  27. /*
  28.  * This is already defined in the new libc.h.  Also, it's now a const.
  29.  * If your version of libc doesn't define it, uncomment the following line:
  30.  *
  31.  * extern const struct section *getsectbyname(char *, char *);
  32.  */
  33.  
  34. /*
  35.  * Kludge: we don't expect any program data beyond VM_HIGHDATA
  36.  * What is really needed is a way to find out from malloc() which
  37.  * pages it vm_allocated and write only those out into the data segment.
  38.  *
  39.  * This kludge may break when we stop using fixed virtual address
  40.  * shared libraries. Actually, emacs will probably continue working, but be 
  41.  * much larger on disk than it needs to be (because non-malloced data will
  42.  * be in the file).
  43.  */
  44.  
  45. static const unsigned VM_HIGHDATA = 0x2000000;
  46.  
  47. typedef struct region_t {
  48.   vm_address_t address;
  49.   vm_size_t size;
  50.   vm_prot_t protection;
  51.   vm_prot_t max_protection;
  52.   vm_inherit_t inheritance;
  53.   boolean_t shared;
  54.   port_t object_name;
  55.   vm_offset_t offset;
  56. } region_t;
  57.  
  58. static void
  59. grow(struct load_command ***the_commands,
  60.      unsigned *the_commands_len)
  61. {
  62.   if (*the_commands == NULL) {
  63.     *the_commands_len = 1;
  64.     *the_commands = malloc(sizeof(*the_commands));
  65.   } else {
  66.     (*the_commands_len)++;
  67.     *the_commands = realloc(*the_commands, 
  68.                 (*the_commands_len *
  69.                  sizeof(**the_commands)));
  70.   }
  71. }
  72.  
  73.  
  74. static void
  75. save_command(struct load_command *command,
  76.          struct load_command ***the_commands,
  77.          unsigned *the_commands_len)
  78. {
  79.   struct load_command **tmp;
  80.   
  81.   grow(the_commands, the_commands_len);
  82.   tmp = &(*the_commands)[*the_commands_len - 1];
  83.   *tmp = malloc(command->cmdsize);
  84.   bcopy(command, *tmp, command->cmdsize);
  85. }
  86.  
  87. static void
  88. fatal_unexec(char *format, ...)
  89. {
  90.   va_list ap;
  91.   
  92.   va_start(ap, format);
  93.   fprintf(stderr, "unexec: ");
  94.   vfprintf(stderr, format, ap);
  95.   fprintf(stderr, "\n");
  96.   va_end(ap);
  97. }
  98.  
  99. static int
  100. read_macho(int fd,
  101.        struct mach_header *the_header,
  102.        struct load_command ***the_commands,
  103.        unsigned *the_commands_len)
  104. {
  105.   struct load_command command;
  106.   struct load_command *buf;
  107.   int i;
  108.   int size;
  109.   
  110.   if (read(fd, the_header, sizeof(*the_header)) != sizeof(*the_header)) {
  111.     fatal_unexec("cannot read macho header");
  112.     return 0;
  113.   }
  114.   for (i = 0; i < the_header->ncmds; i++) {
  115.     if (read(fd, &command, sizeof(struct load_command)) != 
  116.     sizeof(struct load_command)) {
  117.       fatal_unexec("cannot read macho load command header");
  118.       return 0;
  119.     }
  120.     size = command.cmdsize - sizeof(struct load_command);
  121.     if (size < 0) {
  122.       fatal_unexec("bogus load command size");
  123.       return 0;
  124.     }
  125.     buf = malloc(command.cmdsize);
  126.     buf->cmd = command.cmd;
  127.     buf->cmdsize = command.cmdsize;
  128.     if (read(fd, ((char *)buf + 
  129.           sizeof(struct load_command)), 
  130.          size) != size) {
  131.       fatal_unexec("cannot read load command data");
  132.       return 0;
  133.     }
  134.     save_command(buf, the_commands, the_commands_len);
  135.   }
  136.   return 1;
  137. }
  138.  
  139. static int
  140. filldatagap(vm_address_t start_address,
  141.         vm_size_t *size,
  142.         vm_address_t end_address)
  143. {
  144.   vm_address_t address;
  145.   vm_size_t gapsize;
  146.   
  147.   address = (start_address + *size);
  148.   gapsize = end_address - address;
  149.   *size += gapsize;
  150.   if (vm_allocate(task_self(), &address, gapsize,
  151.           FALSE) != KERN_SUCCESS) {
  152.     fatal_unexec("cannot vm_allocate");
  153.     return 0;
  154.   }
  155.   return 1;
  156. }
  157.  
  158. static int
  159. get_data_region(vm_address_t *address,
  160.         vm_size_t *size)
  161. {
  162.   region_t region;
  163.   kern_return_t ret;
  164.   const struct section *sect;    /* Changed to const.  -cws */
  165.   
  166.   sect = getsectbyname(SEG_DATA, SECT_DATA);
  167.   region.address = 0;
  168.   *address = 0;
  169.   for (;;) {
  170.     ret = vm_region(task_self(), 
  171.             ®ion.address, 
  172.             ®ion.size, 
  173.             ®ion.protection, 
  174.             ®ion.max_protection, 
  175.             ®ion.inheritance,
  176.             ®ion.shared, 
  177.             ®ion.object_name, 
  178.             ®ion.offset);
  179.     if (ret != KERN_SUCCESS || region.address >= VM_HIGHDATA) {
  180.       break;
  181.     }
  182.     if (*address) {
  183.       if (region.address > *address + *size) {
  184.     if (!filldatagap(*address, size, 
  185.              region.address)) {
  186.       return 0;
  187.     }
  188.       } 
  189.       *size += region.size;
  190.     } else {
  191.       if (region.address == sect->addr) {
  192.     *address = region.address;
  193.     *size = region.size;
  194.       } 
  195.     }
  196.     region.address += region.size;
  197.   }
  198.   return 1;
  199. }
  200.  
  201. static char *
  202. my_malloc(vm_size_t size)
  203. {
  204.   vm_address_t address;
  205.   
  206.   if (vm_allocate(task_self(), &address, size, TRUE) != KERN_SUCCESS) {
  207.     return (NULL);
  208.   }
  209.   return ((char *)address);
  210. }
  211.  
  212. static void
  213. my_free(char *buf,
  214.     vm_size_t size)
  215. {
  216.   vm_deallocate(task_self(), (vm_address_t)buf, size);
  217. }
  218.  
  219. static int
  220. unexec_doit(int infd,
  221.         int outfd)
  222. {
  223.   int i;
  224.   struct load_command **the_commands = NULL;
  225.   unsigned the_commands_len;
  226.   struct mach_header the_header;
  227.   int fgrowth = 0;
  228.   int fdatastart = 0;
  229.   int fdatasize = 0;
  230.   int size;
  231.   struct stat st;
  232.   char *buf;
  233.   vm_address_t data_address;
  234.   vm_size_t data_size;
  235.   
  236.   struct segment_command *segment;
  237.   
  238.   if (!read_macho(infd, &the_header, &the_commands, &the_commands_len))
  239.     return 0;
  240. {
  241.   extern int malloc_cookie;
  242.   malloc_cookie = malloc_freezedry();
  243. }
  244.   
  245.   if (!get_data_region(&data_address, &data_size))
  246.     return 0;
  247.   
  248.   /*
  249.    * DO NOT USE MALLOC IN THIS SECTION
  250.    */
  251.  
  252.   /*
  253.    * Fix offsets
  254.    */
  255.   for (i = 0; i < the_commands_len; i++) {
  256.     switch (the_commands[i]->cmd) {
  257.     case LC_SEGMENT:
  258.       segment = ((struct segment_command *)
  259.          the_commands[i]);
  260.       if (strcmp(segment->segname, SEG_DATA) == 0) {
  261.     fdatastart = segment->fileoff;
  262.     fdatasize = segment->filesize;
  263.     fgrowth = (data_size - 
  264.            segment->filesize);
  265.     segment->vmsize = data_size;
  266.     segment->filesize = data_size;
  267.       }
  268.       break;
  269.  
  270.     case LC_SYMTAB:
  271.       ((struct symtab_command *)
  272.        the_commands[i])->symoff += fgrowth;
  273.       ((struct symtab_command *)
  274.        the_commands[i])->stroff += fgrowth;
  275.       break;
  276.  
  277.     case LC_SYMSEG:
  278.       ((struct symseg_command *)
  279.        the_commands[i])->offset += fgrowth;
  280.       break;
  281.  
  282.     default:
  283.       break;
  284.     }
  285.   }
  286.   
  287.   /*
  288.    * Write header
  289.    */
  290.   
  291.   if (write(outfd, &the_header,
  292.         sizeof(the_header)) != sizeof(the_header)) {
  293.     fatal_unexec("cannot write output file");
  294.     return 0;
  295.   }
  296.   
  297.   /*
  298.    * Write commands
  299.    */
  300.   
  301.   for (i = 0; i < the_commands_len; i++) {
  302.     if (write(outfd, the_commands[i], 
  303.           the_commands[i]->cmdsize) != 
  304.     the_commands[i]->cmdsize) {
  305.       fatal_unexec("cannot write output file");
  306.       return 0;
  307.     }
  308.   }
  309.   
  310.   /*
  311.    * Write original text
  312.    */
  313.   
  314.   if (lseek(infd, the_header.sizeofcmds + sizeof(the_header), L_SET) < 0) {
  315.     fatal_unexec("cannot seek input file");
  316.     return 0;
  317.   }
  318.   
  319.   size = fdatastart - (sizeof(the_header) + 
  320.                the_header.sizeofcmds);
  321.   buf = my_malloc(size);
  322.   
  323.   if (read(infd, buf, size) != size) {
  324.     my_free(buf, size);
  325.     fatal_unexec("cannot read input file");
  326.   }
  327.   
  328.   if (write(outfd, buf, size) != size) {
  329.     my_free(buf, size);
  330.     fatal_unexec("cannot write output file");
  331.     return 0;
  332.   }
  333.   my_free(buf, size);
  334.   
  335.   /*
  336.    * Write new data
  337.    */
  338.   if (write(outfd, (char *)data_address, 
  339.         data_size) != data_size) {
  340.     fatal_unexec("cannot write output file");
  341.     return 0;
  342.   }
  343.   
  344.   /*
  345.    * OKAY TO USE MALLOC NOW
  346.    */
  347.   
  348.   /*
  349.    * Write rest of file
  350.    */
  351.   
  352.   fstat(infd, &st);
  353.   if (lseek(infd, fdatasize, L_INCR) < 0) {
  354.     fatal_unexec("cannot seek input file");
  355.     return 0;
  356.   }
  357.   size = st.st_size - lseek(infd, 0, L_INCR);
  358.   
  359.   buf = malloc(size);
  360.   if (read(infd, buf, size) != size) {
  361.     free(buf);
  362.     fatal_unexec("cannot read input file");
  363.     return 0;
  364.   }
  365.   if (write(outfd, buf, size) != size) {
  366.     free(buf);
  367.     fatal_unexec("cannot write output file");
  368.     return 0;
  369.   }
  370.   
  371.   free(buf);
  372.   return 1;
  373. }
  374.  
  375. void
  376. unexec (char *outfile,
  377.         char *infile)
  378. {
  379.   int infd;
  380.   int outfd;
  381.   char tmpbuf[L_tmpnam];
  382.   char *tmpfile;
  383.   
  384.   infd = open(infile, O_RDONLY, 0);
  385.   if (infd < 0) {
  386.     fatal_unexec("cannot open input file `%s'", infile);
  387.     exit(1);
  388.   }
  389.   
  390.   tmpnam(tmpbuf);
  391.   tmpfile = rindex(tmpbuf, '/');
  392.   if (tmpfile == NULL) {
  393.     tmpfile = tmpbuf;
  394.   } else {
  395.     tmpfile++;
  396.   }
  397.  
  398.   outfd = open(tmpfile, O_WRONLY|O_TRUNC|O_CREAT, 0755);
  399.   if (outfd < 0) {
  400.     close(infd);
  401.     fatal_unexec("cannot open tmp file `%s'", tmpfile);
  402.     exit(1);
  403.   }
  404.   if (!unexec_doit(infd, outfd)) {
  405.     close(infd);
  406.     close(outfd);
  407.     unlink(tmpfile);
  408.     exit(1);
  409.   }
  410.   close(infd);
  411.   close(outfd);
  412.   if (rename(tmpfile, outfile) < 0) {
  413.     unlink(tmpfile);
  414.     fatal_unexec("cannot rename `%s' to `%s'", tmpfile, outfile);
  415.     exit(1);
  416.   }
  417. }
  418. #endif
  419.